#include "util.hh"
#include "expression.hh"
#include <boost/ptr_container/ptr_vector.hpp>
#include <boost/shared_ptr.hpp>
#include <vector>
#include <numeric>

#ifndef EXPRESSION_TUPLE
#define EXPRESSION_TUPLE

// data structure for multiple expression vectors
// - vectors could have different sizes
struct
expr_tuple_t
{
  typedef double value_type;
  typedef std::vector<value_type> vec_type;
  typedef boost::ptr_vector< vec_type > mat_type;

  expr_tuple_t(const int _id, const size_t p) : id(_id), num_vectors(p) {
    for(size_t j=0; j<num_vectors; ++j)
      vectors.push_back( new vec_type );
  }

  const int id;
  const size_t num_vectors;
  mat_type vectors;
    
  size_t size() const { return num_vectors; }
};

#ifdef DEBUG
void
dump( const expr_tuple_t& expr_tuple )
{
  for(size_t j=0; j<expr_tuple.size(); ++j)
  {
    const expr_tuple_t::vec_type& vec = expr_tuple.vectors.at(j);
    for(size_t v=0; v<vec.size(); ++v)
    {
      std::cerr << "\t" << vec.at(v);
    }
    std::cerr << std::endl;
  }
}
#endif

// expression tuple set
typedef expr_ptr_set_t< expr_tuple_t > expr_tuple_set_t;
typedef expr_ptr_set_iterator_t< expr_tuple_t > expr_tuple_set_iter_t;

expr_tuple_set_iter_t begin( const expr_tuple_set_t& tuple_set )
{
  return expr_tuple_set_iter_t( tuple_set.begin() );
}

expr_tuple_set_iter_t end( const expr_tuple_set_t& tuple_set )
{
  return expr_tuple_set_iter_t( tuple_set.end() );
}

// I/O
typedef std::vector< boost::shared_ptr< expr_tuple_t > > expr_tuple_vec_t;

bool read_expr_tuple( const char* data_file,
		      const std::vector<size_t>& ncols,
		      expr_tuple_vec_t& out )
{
  // error checking
  if( ncols.size() == 0 ) return false;

  size_t n = num_rows( data_file );
  size_t p = num_columns( data_file );

  TLOG( "data matrix " << n << " x " << p );
  
  std::vector<size_t> cumcols(ncols.size());
  std::partial_sum( ncols.begin(), ncols.end(), cumcols.begin() );

  if( p != cumcols[ cumcols.size() - 1 ] ) return false;

  // read data stream
  // x_1 x_2 .. x_nA, y_1 y_2 .. y_nB, z_1 z_2 .. z_nC .. and more
  // keep track of blocks 
  double x;
  std::ifstream ifs( data_file, std::ios::in );

  int id = -1;
  size_t curr_block = 0;
  size_t num_blocks = cumcols.size();
  size_t pos;
  boost::shared_ptr< expr_tuple_t > curr_tuple;
  for( size_t j=0 ; ifs >> x ; ++j )
  {
    pos = j % p;
    if( pos == 0 ){
      curr_block = 0;
      curr_tuple = boost::shared_ptr<expr_tuple_t>( new expr_tuple_t(++id, num_blocks) );
      out.push_back( curr_tuple );
    }
    else if( cumcols[curr_block] <= pos ){
      curr_block = (curr_block + 1) % num_blocks;
    }
    curr_tuple->vectors[ curr_block ].push_back( x );
  }  
  ifs.close();

  if( pos < (p-1) ) TLOG("warning: may have incomplete data");
  
  return true;
}


#endif
